import { PlusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import React, { useMemo, useState } from 'react';
import { NodeProps } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import { t } from '@/locales/i18n';
import {
  AllFlowValueTypeMap,
  FlowNodeInputMap,
  FlowNodeInputTypeEnum,
  FlowNodeOutputTypeEnum,
} from '@/types/workflow/constant';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '@/types/workflow/io';
import { FlowNodeItemType } from '@/types/workflow/node';

import { WorkflowContext } from '../../../context';
import Container from '../../flow/Container';
import IOTitle from '../../flow/IOTitle';
import NodeCard from '../render/NodeCard';
import RenderOutput from '../render/RenderOutput';

import FieldEditModal, { defaultInput } from './InputEditModal';
import VariableTable from './VariableTable';

// const FieldEditModal = React.lazy(() => import('./InputEditModal'));

/* 
  1.调用插件时，对渲染节点的输入进行自定义。
  2.自定义输入节点。输入和输出必须对称。
  3.运行插件时，外部将计算自定义输入的值，并将其抛给自定义输入节点的输出，以开始运行插件。
*/

function NodePluginInput({ data, selected }: NodeProps<FlowNodeItemType>) {
  const { nodeId, inputs = [], outputs } = data;

  const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);

  const [editField, setEditField] = useState<FlowNodeInputItemType>();

  const onSubmit = (data: FlowNodeInputItemType) => {
    if (!editField) return;

    if (editField?.key) {
      const output = outputs.find((output) => output.key === editField.key);
      const newOutput: FlowNodeOutputItemType = {
        ...(output as FlowNodeOutputItemType),
        valueType: data.valueType,
        key: data.key,
        label: data.label,
      };
      onChangeNode({
        nodeId,
        type: 'replaceInput',
        key: editField.key,
        value: data,
      });
      onChangeNode({
        nodeId,
        type: 'replaceOutput',
        key: editField.key,
        value: newOutput,
      });
    } else {
      const newOutput: FlowNodeOutputItemType = {
        id: data.key,
        valueType: data.valueType,
        key: data.key,
        label: data.label,
        type: FlowNodeOutputTypeEnum.hidden,
      };

      // add_new_input
      onChangeNode({
        nodeId,
        type: 'addInput',
        value: data,
      });
      onChangeNode({
        nodeId,
        type: 'addOutput',
        value: newOutput,
      });
    }
  };

  const Render = useMemo(() => {
    return (
      <NodeCard
        minW="300px"
        selected={selected}
        menuForbid={{
          copy: true,
          delete: true,
        }}
        {...data}
      >
        <Container className="mt-1">
          <div className="nodrag mb-3 flex cursor-default">
            <IOTitle text={t('core.workflow.Custom inputs')} className="mb-0" />
            <div className="flex-1" />
            <Button
              type="text"
              icon={<PlusOutlined />}
              onClick={() => setEditField(defaultInput)}
            />
          </div>
          <VariableTable
            variables={inputs.map((input) => {
              const inputType = input.renderTypeList[0];
              return {
                icon: FlowNodeInputMap[inputType]?.icon as string,
                label: t(input.label as any),
                type: input.valueType ? t(AllFlowValueTypeMap[input.valueType]?.label as any) : '-',
                isTool: !!input.toolDescription,
                key: input.key,
              };
            })}
            onEdit={(key) => {
              const input = inputs.find((input) => input.key === key);
              if (!input) return;
              setEditField(input);
            }}
            onDelete={(key) => {
              onChangeNode({
                nodeId,
                type: 'delInput',
                key,
              });
              onChangeNode({
                nodeId,
                type: 'delOutput',
                key,
              });
            }}
          />
        </Container>
        {!!outputs.length && (
          <Container>
            <IOTitle text={t('common.Output')} />
            <RenderOutput nodeId={nodeId} flowOutputList={outputs} />
          </Container>
        )}
      </NodeCard>
    );
  }, [data, inputs, nodeId, onChangeNode, outputs, selected]);

  return (
    <>
      {Render}
      {!!editField && (
        <FieldEditModal
          defaultValue={editField}
          keys={inputs.map((item) => item.key)}
          hasDynamicInput={
            !!inputs.find(
              (input) =>
                input.key !== editField.key &&
                input.renderTypeList.includes(FlowNodeInputTypeEnum.addInputParam),
            )
          }
          onClose={() => setEditField(undefined)}
          onSubmit={onSubmit}
        />
      )}
    </>
  );
}
export default React.memo(NodePluginInput);
